package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.heima.aliyun.scan.GreenScan;
import com.heima.aliyun.scan.ScanResult;
import com.heima.commom.constants.message.PublishArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.model.admin.dtos.SensitiveDTO;
import com.heima.model.admin.pojos.AdSensitive;
import com.heima.model.common.constants.wemedia.WmMaterialConstant;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Value("${file.oss.web-site}")
    private String webSite;
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private GreenScan greenScan;
    @Autowired
    private AdminFeign adminFeign;

    @Autowired
    RabbitTemplate rabbitTemplate;
    /**
     *  文章自动审核
     * @param id  自媒体文章id
     */
    @Override
    public void autoScanWmNews(Integer id) {
        if(id == null){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"待审核的文章id为空");
        }
        WmNews wmNews = wmNewsMapper.selectById(id);
        if(wmNews == null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"待审核的文章查询错误 文章不存在");
        }
        //判断文章的状态
        if(!WmMaterialConstant.WM_NEWS_SUMMIT_STATUS.equals(wmNews.getStatus())){
            log.info("待审核的文章状态为:{} 无需审核",wmNews.getStatus());
            return;
        }
        //抽取文章中的文本内容 和 图片内容
        Map<String, Object> textAndMessage = getTextAndMessage(wmNews);
        //检查文本内容是否有敏感词违规
            //从抽取的内容中获取到文本内容
        String content = (String)textAndMessage.get("content");
        boolean textFlag = ReviewViolationsText(content, wmNews);
        if(!textFlag){
            log.info("文章未通过敏感词审核");
            return;
        }

        //使用阿里云 审核文本内容是否违规
        boolean violationsText = AliReviewViolationsText(content, wmNews);
        if(!violationsText){
            log.info("阿里云审核有违规 未通过");
            return;
        }
        //检查图片内容是否有违规
        //获取到图片内容
        List<String> images = (List<String>)textAndMessage.get("images");
        boolean imagesFlag = AliReviewViolationsImages(images, wmNews);
        if(!imagesFlag){
            log.info("阿里云 图片审核未通过");
            return;
        }
        //自动审核成功
        updateWmNews(WmNews.Status.SUCCESS.getCode(), "自动审核通过",wmNews);

        //通知定时发布任务
        //发布时间
        long publishTime = wmNews.getPublishTime().getTime();
        //当前时间
        long nowTime = new Date().getTime();
        //设置延迟发布任务时间
        long remainTime = publishTime - nowTime ;
        //发布文章消息
        rabbitTemplate.convertAndSend(PublishArticleConstants.DELAY_DIRECT_EXCHANGE //设置交换机
                ,PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY                  // 设置路由key
                ,wmNews.getId()     //发送的消息
                ,(message -> {      // 设置延时时间 如果 发布时间小于当前时间 设为0
                    message.getMessageProperties().setHeader("x-delay",remainTime <= 0 ? 0 : remainTime);
                    return message;
                }));
        log.info("发布文章的通知消息 成功发送 文章的id为:{}",wmNews.getId());
    }

    private boolean AliReviewViolationsImages(List<String> images, WmNews wmNews){
        boolean flag = false;
        try {
            ScanResult scanResult = greenScan.imageUrlScan(images);
            String suggestion = scanResult.getSuggestion();
            switch (suggestion){
                case "block":
                    updateWmNews(WmNews.Status.FAIL.getCode(), "文章图片中有违规信息",wmNews);
                    break;
                case "review":
                    updateWmNews(WmNews.Status.ADMIN_AUTH.getCode(), "文章图片中有不明确信息,需人工审核",wmNews);
                    break;
                case "pass":
                    flag = true;
                    break;
                default:
                    updateWmNews(WmNews.Status.ADMIN_AUTH.getCode(), "阿里云审核图片响应状态异常,需人工审核",wmNews);
            }
        } catch (Exception e) {
            updateWmNews(WmNews.Status.ADMIN_AUTH.getCode(), "阿里云审核图片异常,需人工审核",wmNews);
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 阿里云审核文本内容是否违规
     * @param text 待审核文本内容
     * @param wmNews 文章对象
     * @return 返回结果
     */
    private boolean AliReviewViolationsText(String text,WmNews wmNews){
        boolean flag = false;
        try {
            ScanResult scanResult = greenScan.greenTextScan(text);
            String suggestion = scanResult.getSuggestion();
            switch (suggestion){
                case "block":
                    updateWmNews(WmNews.Status.FAIL.getCode(), "文章内容中包含违规词汇: "+scanResult.getLabel(),wmNews);
                    break;
                case "review":
                    updateWmNews(WmNews.Status.ADMIN_AUTH.getCode(), "文章内容中包含不确定因素,需要人工审核",wmNews);
                    break;
                case "pass":
                    flag = true;
                    break;
                default:
                    updateWmNews(WmNews.Status.ADMIN_AUTH.getCode(), "阿里云调用响应状态异常,需要人工审核",wmNews);
                    break;
            }
        } catch (Exception e) {
            updateWmNews(WmNews.Status.ADMIN_AUTH.getCode(), "阿里云文本审核调用异常,人工审核",wmNews);
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 查询 文本内容是否包含敏感词汇
     * @param text 文章中的内容
     * @param wmNews 文章对象
     * @return 返回 true 或 false
     */
    private boolean ReviewViolationsText(String text,WmNews wmNews){
        boolean flag = true;
            //远程调用查询管理的敏感词汇
        ResponseResult<List<String>> sensitives = adminFeign.sensitives();
        if (!sensitives.checkCode()) {
            log.error("远程调用 查询敏感词时出错");
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
        }
        //获取到敏感词
        List<String> data = sensitives.getData();
       // 将敏感词 转为DFA数据模型
        SensitiveWordUtil.initMap(data);

        //基于DFA扫描 内容中是否有敏感词汇
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
        //如果有敏感词汇 将更新文章状态 告知原因
        if(CollectionUtils.isNotEmpty(map)){
            updateWmNews(WmNews.Status.FAIL.getCode(), "包含敏感词汇"+map,wmNews);
            flag = false;
        }
        return flag;
    }

    //更新文章状态
    private void updateWmNews(Short status,String reason,WmNews wmNews){
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 抽取文章中的文本内容和图片素材
     * @param wmNews 文章对象
     * @return 返回文本内容 和 图片路径内容
     */
    private Map<String,Object> getTextAndMessage(WmNews wmNews){
        Map<String,Object> map = new HashMap<>();

        //获取文章中的内容
        String wmNewsContent = wmNews.getContent();
        if(StringUtils.isBlank(wmNewsContent)){
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE,"文章内容不能为空");
        }
        //将文章内容转为集合
        List<Map> mapList = JSON.parseArray(wmNewsContent, Map.class);

        //抽取 内容中的文本信息
        String collect = mapList.stream()
                .filter(map1 -> "text".equals(map1.get("type")))
                .map(map1 -> map1.get("value").toString())
                .collect(Collectors.joining("_hi_"));
        //将标题和文本内容拼接起来
        collect = wmNews.getTitle()+"_hi_"+ collect;
        //抽取 内容中的图片内容
        List<String> images = mapList.stream()
                .filter(map1 -> "image".equals(map1.get("type")))
                .map(map1 -> map1.get("value").toString())
                .collect(Collectors.toList());

        //抽取封面中的图片
        String images1 = wmNews.getImages();
        if(StringUtils.isNotBlank(images1)){
            List<String> strings = Arrays.stream(images1.split(","))
                    .map(url -> url + webSite)
                    .collect(Collectors.toList());
            //将封面中的图片和内容中的图片合并
            images.addAll(strings);
        }
        //将照片去重
        images = images.stream().distinct().collect(Collectors.toList());

        //将文本内容放进map中
        map.put("content",collect);
        //将图片 路径 放进集合
        map.put("images",images);
        return map;
    }
}
